import json
import random

from itsdangerous import base64_encode, base64_decode
from django import http
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.views import View
from django_redis import get_redis_connection
# from meiduo_mall.utils.response_code import *
from carts.utils import merge_cookie_redis_data
from celery_tasks.mail.tasks import send_verify_email
from meiduo_mall.utils import constants, sinaweibopy3
from meiduo_mall.utils.my_encrypt import generate_verify_url, decode_verify_url
from meiduo_mall.utils.my_loginview import LoginreqyiredView
from meiduo_mall.utils.response_code import RET
from users.models import User, Address
from meiduo_mall.utils.my_password import *
from verifications.views import SMSCodeView
import re


class Register(View):
    def get(self, request):
        return render(request, 'register.html')
        # return render(request, 'register.html')

    def post(self, request):
        # 获取post请求方式表单的数据
        user_name = request.POST.get('user_name')
        pwd = request.POST.get('pwd')
        cpwd = request.POST.get('cpwd')
        phone = request.POST.get('phone')
        msg_code = request.POST.get('msg_code')
        allow = request.POST.get('allow')
        print(msg_code)
        print(allow)
        if not all([user_name, pwd, cpwd, phone, msg_code, allow]):
            return http.HttpResponseForbidden('参数不全')
        if pwd != cpwd:
            return http.HttpResponseForbidden('密码不一致')
        if not re.match('^1[3-9]\d{9}$', phone):
            return http.HttpResponseForbidden('手机号码格式错误')
        # if not msg_code == '123':
        #     return http.HttpResponseForbidden('验证码错误')
        if not allow == 'on':
            return http.HttpResponseForbidden('未勾选协议')
        redis_sms_code = get_redis_connection('code')  # 连接对应存储验证码的redis库

        if msg_code != redis_sms_code.get("sms_code_%s" % phone).decode():
            return http.HttpResponseForbidden('短信验证码错误')
        User.objects.create_user(username=user_name, password=pwd, mobile=phone)

        return redirect('/login/')


# 注册时检查用户名有没有被使用
class CheckUsernameView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code': RET.OK, 'errmsg': 'OK', 'count': count})


# 注册时检查手机号有没有被使用
class CheckMobleView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'count': count, 'code': 0})


# 登陆视图
class LoginView(View):
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        # 获取用户参数
        username = request.POST.get("username")
        pwd = request.POST.get("pwd")
        remembered = request.POST.get("remembered")  # 是否勾选记住登录

        if not all([username, pwd]):
            return http.HttpResponseForbidden('用户名或密码未填')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}', username):
            return http.HttpResponseForbidden('用户名格式错误')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}', pwd):
            return http.HttpResponseForbidden('密码格式错误')
        user = authenticate(username=username, password=pwd, request=request)
        if not user:
            return http.HttpResponseForbidden('用户名或密码错误')

        # 保持用户登录状态 是指 lonin(request, user) == request.user = user
        login(request, user)  # 就是将用户的信息存储在session
        if remembered == "on":
            request.session.set_expiry(3600 * 24 * 2)  # 两天
        else:
            request.session.set_expiry(0)  # 一次浏览器会话结束

        to_url = request.GET.get("redirect_to", "/")
        response = redirect(to_url)
        response.set_cookie('username', user.username, max_age=constants.USER_LOGIN_COOKIE_EXPIRES)
        # 合并购物车
        response = merge_cookie_redis_data(request, response)
        return response


class UserInfoView(LoginreqyiredView, View):
    def get(self, request):
        # request.user表示当前登录的用户
        context = {
            "username": request.user.username,
            "mobile": request.user.mobile,
            "email": request.user.email,
            "email_active": request.user.email_avtive,
        }
        if request.user.is_authenticated:
            # render的作用将context数据渲染到html页面
            return render(request, 'user_center_info.html', context=context)
        else:
            return redirect('/login/')


# 发送邮件 验证邮箱
class EmailView(LoginreqyiredView, View):
    def get(self, request):
        """
        验证邮件链接
        :param request:
        :return:
        """
        token = request.GET.get('token')
        user = decode_verify_url(token)
        if not user:
            return http.HttpResponseForbidden('token失效')
        user.email_avtive = True
        user.save()
        return redirect('/info/')

    def put(self, request):
        """
        发送邮件
        :param request:
        :return:
        """
        email = json.loads(request.body.decode()).get('email')
        if not email:
            return http.JsonResponse({'code': RET.NECESSARYPARAMERR, 'errmsg': "未填写邮箱"})
        verify_url = generate_verify_url(request.user, email)  # 加密验证链接
        send_verify_email.delay(verify_url, email)  # 发送邮件
        # if result != 1:
        #     return http.JsonResponse({'code': RET.NECESSARYPARAMERR, 'errmsg': "验证链接发送失败"})
        request.user.email = email
        request.user.save()
        return http.JsonResponse({'code': RET.OK, 'errmsg': "邮件发送成功"})


# 显示全部地址
class AddressesView(LoginreqyiredView, View):
    def get(self, request):
        # Address.objects.filter(user_id=request.user.id)
        addresses = request.user.addresses.all()  # 新写法
        addresses_list = []
        for address in addresses:
            address_dict = {
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
                'province_id': address.province_id,
                'city_id': address.city_id,
                'district_id': address.district_id,
            }
            addresses_list.append(address_dict)
        context = {
            'addresses': addresses_list

        }
        return render(request, 'user_center_site.html', context=context)
        my


# 新增地址
class AddressesCreateView(View):
    def post(self, request):
        data_dict = json.loads(request.body.decode())
        title = data_dict.get("title")
        receiver = data_dict.get("receiver")
        province_id = data_dict.get("province_id")
        city_id = data_dict.get("city_id")
        district_id = data_dict.get("district_id")
        place = data_dict.get("place")
        mobile = data_dict.get("mobile")
        tel = data_dict.get("tel")
        email = data_dict.get("email")

        if not all([title, receiver, province_id, city_id, district_id, place, mobile, tel, email]):
            return http.JsonResponse({'code': RET.NECESSARYPARAMERR, 'errmsg': '参数不全'})
        data_dict['user_id'] = request.user.id
        try:
            address = Address.objects.create(**data_dict)
        except Exception as e:
            return http.JsonResponse({'code': RET.DATAERR, "errmsg": "创建失败"})
        data_dict = {
            'code': RET.OK,
            'address': {
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
                'province_id': address.province_id,
                'city_id': address.city_id,
                'district_id': address.district_id,

            }
        }
        return http.JsonResponse(data_dict)


# 修改地址
class AddressesUpdateView(View):
    def put(self, request, user_id):
        data_dict = json.loads(request.body.decode())
        title = data_dict.get("title")
        receiver = data_dict.get("receiver")
        province_id = data_dict.get("province_id")
        city_id = data_dict.get("city_id")
        district_id = data_dict.get("district_id")
        place = data_dict.get("place")
        mobile = data_dict.get("mobile")
        tel = data_dict.get("tel")
        email = data_dict.get("email")

        if not all([title, receiver, province_id, city_id, district_id, place, mobile, tel, email]):
            return http.JsonResponse({'code': RET.NECESSARYPARAMERR, 'errmsg': '参数不全'})
        try:
            del data_dict['id']
            del data_dict['province']
            del data_dict['city']
            del data_dict['district']
            ret = Address.objects.filter(id=user_id).update(**data_dict)
            address = Address.objects.get(id=user_id)
            print('修改了%s数据' % ret)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '修改失败'})
        data_dict = {
            'code': RET.OK,
            'address': {
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
                'province_id': address.province_id,
                'city_id': address.city_id,
                'district_id': address.district_id,

            }
        }
        return http.JsonResponse(data_dict)

    def delete(self, request, address_id):
        try:
            ret = Address.objects.filter(id=address_id).update(is_deleted=True)
        except Exception as e:
            return http.JsonResponse({"code": RET.DBERR, "errmsg": "删除失败"})

        return http.JsonResponse({"code": RET.OK, "errmsg": "删除成功"})


# 设置默认
class AddressesDefaultView(LoginreqyiredView, View):
    def put(self, request, address_id):
        try:
            request.user.default_address_id = address_id
            request.user.save()
        except Exception as e:
            return http.JsonResponse({'code': RET.DATAERR, 'errmsg': '设置默认地址失败'})
        return http.JsonResponse({'code': RET.OK, 'errmsg': '修改成功'})


# 用户中心修改密码
class UserPassWord(LoginreqyiredView, View):
    def get(self, request):
        return render(request, 'user_center_pass.html')
        # Create your views here.

    def post(self, request):
        # 获取参数
        old_pwd = request.POST.get('old_pwd')
        new_pwd = request.POST.get('new_pwd')
        new_cpwd = request.POST.get('new_cpwd')
        if not all([old_pwd, new_cpwd, new_pwd]):
            return render(request, 'user_center_pass.html')
        if new_pwd != new_cpwd:
            return render(request, 'user_center_pass.html')
        if old_pwd == new_pwd:
            return render(request, 'user_center_pass.html')
        if not request.user.check_password(old_pwd):
            return render(request, 'user_center_pass.html')
        request.user.set_password(new_pwd)
        request.user.save()
        response = redirect('/login/')
        logout(request)  # 清楚session
        response.delete_cookie('user_name')
        return response


# 找回密码界面
class FindPassWordView(View):
    def get(self, request):
        return render(request, "find_password.html")


# 验证找回密码图形验证码
class AccountsView(View):
    def get(self, request, username):
        image_code_client = request.GET.get("text")  # 图形验证码的数字
        uuid = request.GET.get("image_code_id")

        # 校验参数
        if not all([image_code_client, uuid]):
            return http.JsonResponse({'code': RET.NECESSARYPARAMERR, 'errmsg': '缺少必传参数'})

        if not re.match(r'[a-zA-Z0-9_-]{5,20}', username):
            return http.JsonResponse({'code': RET.MOBILEERR, 'errmsg': '用户名格式错误'})

        # 取出redis验证码标记比对
        redis_conn = get_redis_connection('code')
        pipeline = redis_conn.pipeline()
        redis_cli_code = redis_conn.get('img_%s' % uuid)
        redis_cli_code = redis_cli_code.decode()

        if image_code_client.upper() != redis_cli_code.upper():  # upper忽略大小写
            return http.JsonResponse({'code': RET.DATAERR, 'errmsg': '图形验证码错误'}, status=400)
        if not redis_cli_code:
            return http.JsonResponse({'code': RET.DATAERR, 'errmsg': '图片验证码已过期'}, status=400)
        try:
            user = User.objects.get(username=username)
        except Exception as e:
            return http.JsonResponse({'code': RET.DATAERR, 'errmsg': '用户不存在啊'}, status=401)

        token = {
            "username": user.username,
            "user_mobile": user.mobile
        }
        access_token = encode_password(token)
        # context = {
        #     "code": RET.OK,
        #     "mobile": user.mobile,
        #     "access_token": access_token,
        #     "user_id": user.id
        # }
        pipeline.execute()
        return http.JsonResponse({
            "code": RET.OK,
            "mobile": user.mobile,
            "access_token": access_token,
            "user_id": user.id
        })


# 发送短信验证码
class SMSPasswordView(View):
    def get(self, request):
        access_token = request.GET.get("access_token")

        # 校验参数
        if not access_token:
            http.JsonResponse({"code": RET.NECESSARYPARAMERR, "message": "缺少重要参数"})

        token = decode_password(access_token)
        username = token["username"]
        mobile = token["user_mobile"]
        try:
            user = User.objects.get(username=username, mobile=mobile)
        except Exception as e:
            http.JsonResponse({"code": RET.NECESSARYPARAMERR, "message": "密钥错误"})

        redis_conn = get_redis_connection('code')
        pipeline = redis_conn.pipeline()
        redis_cli_flag = redis_conn.get("redis_cli_flag%s" % mobile)  # 将手机号码打上标记，防止频繁发送短信验证码
        if redis_cli_flag:
            return http.JsonResponse({"code": RET.REQERR, "message": "请勿频繁发送短信"}, status=401)
        else:
            sms_code = '%06d' % random.randint(0, constants.SMS_CODE_EXPIRES)
            print(sms_code)
            # 3,1 设置标记,防止1分钟之内, 短信多次发送
            pipeline.set("sms_code_%s" % mobile, sms_code, constants.REDIS_SMS_CODE_EXPIRES)  # 将短信验证码存入redis留作判断是否正确
            # 发送验证码
            # from celery_tasks.sms.tasks import send_message  # 等待调试
            # send_message.delay(mobile, sms_code)
            pipeline.set("redis_cli_flag%s" % mobile, 1, constants.REDIS_MOBILE_SMS_CODE_EXPIRES)
            pipeline.execute()  # 最后通过pipeline管道提交数据的redis
            context = {
                'code': RET.OK,
                'errmsg': '发送短信成功',
            }
            return http.JsonResponse(context)


# 验证短信验证码
class VerirySMSView(View):
    def get(self, request, username):
        user_sms_code = request.GET.get("sms_code")

        if not user_sms_code:
            return http.JsonResponse({"code": RET.DATAERR, "message": "未填写短信验证码"}, status=401)

        try:
            user = User.objects.get(username=username)
        except Exception as e:
            return http.JsonResponse({"code": RET.DATAERR, "message": "用户不存在"}, status=401)

        redis_conn = get_redis_connection('code')
        redis_sms = redis_conn.get("sms_code_%s" % user.mobile)
        if user_sms_code != redis_sms.decode():
            return http.JsonResponse({"code": RET.DATAERR, "message": "短信验证码错误"}, status=400)
        else:
            token = {
                "username": user.username,
                "user_mobile": user.mobile
            }
            access_token = encode_password(token)
            context = {
                "message": "短信验证通过",
                "access_token": access_token,
                "user_id": user.id
            }
            return http.JsonResponse(context)


# 修改密码
class VeriryPasswordView(View):
    def post(self, request, user_id):
        # 获取用户新密码
        dict = json.loads(request.body.decode())
        new_password = dict.get("password")
        new_password2 = dict.get("password2")
        access_token = dict.get("access_token")

        # 校验参数
        if not all([new_password, new_password2]):
            return http.JsonResponse({"message": "参数不全"}, status=401)

        if new_password != new_password2:
            return http.JsonResponse({"message": "两次输入密码不一致"}, status=401)

        token = decode_password(access_token)
        username = token["username"]
        mobile = token["user_mobile"]
        try:
            user = User.objects.get(username=username, mobile=mobile, id=user_id)
        except Exception as e:
            http.JsonResponse({"code": RET.NECESSARYPARAMERR, "message": "密钥错误"})

        user.set_password(new_password)
        user.save()
        return http.JsonResponse({"message": "修改密码成功"})

